/*
 * Copyright 2011-2012 Rivoli team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.rivoli.reader.aluminum

import com.googlecode.aluminumproject.Aluminum
import com.googlecode.aluminumproject.AluminumException
import com.googlecode.aluminumproject.configuration.ConfigurationParameters
import com.googlecode.aluminumproject.configuration.DefaultConfiguration
import com.googlecode.aluminumproject.context.Context
import com.googlecode.aluminumproject.context.DefaultContext
import com.googlecode.aluminumproject.writers.ListWriter
import com.googlecode.rivoli.RivoliException
import com.googlecode.rivoli.model.Element
import com.googlecode.rivoli.model.Model
import com.googlecode.rivoli.reader.DefinitionReader

class AluminumDefinitionReader implements DefinitionReader {
	private Aluminum aluminum

	private String parser

	void init(Map<String, ?> parameters) throws RivoliException {
		parser = parameters[PARSER] ?: 'aluscript'

		Map<String, String> aluminumParameters = parameters[ALUMINUM_PARAMETERS] ?: [:]

		Set<String> configurationElementPackages = [] as Set

		if (aluminumParameters.containsKey(DefaultConfiguration.CONFIGURATION_ELEMENT_PACKAGES)) {
			configurationElementPackages.addAll(aluminumParameters[DefaultConfiguration.CONFIGURATION_ELEMENT_PACKAGES].split(/\s*,\s*/))
		}

		configurationElementPackages << 'com.googlecode.rivoli.reader.aluminum'

		aluminumParameters[DefaultConfiguration.CONFIGURATION_ELEMENT_PACKAGES] = configurationElementPackages.toList().join(',')

		try {
			aluminum = new Aluminum(new DefaultConfiguration(aluminumParameters.inject(new ConfigurationParameters()) {ConfigurationParameters configurationParameters, Map.Entry<String, String> parameter ->
				configurationParameters.addParameter(parameter.key, parameter.value)

				configurationParameters
			}))
		} catch (AluminumException exception) {
			throw new RivoliException('could not initialise Aluminum', exception)
		}
	}

	Element read(String name, Model model, Map<String, ?> data) throws RivoliException {
		Context context = new DefaultContext()
		context.addImplicitObject(MODEL, model)

		data.each {String variable, Object value ->
			context.setVariable(variable, value)
		}

		ListWriter writer = new ListWriter()

		try {
			aluminum.processTemplate(name, parser, context, writer)
		} catch (AluminumException exception) {
			throw new RivoliException("reading definition '${name}' failed", exception)
		}

		def element = (writer.list.size() == 1) ? writer.list.first() : null

		if (!(element in Element)) {
			throw new RivoliException("definition '${name}' does not contain a single element")
		}

		element
	}

	final static String PARSER = 'parser'
	final static String ALUMINUM_PARAMETERS = 'aluminum parameters'

	final static String MODEL = 'model'
}